package service

import (
	"KD_web/go/dao"
	"KD_web/go/entity"
	"KD_web/go/errors"
	"fmt"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
	"math/rand"
	"regexp"
	"strconv"
	"time"
)

// user information

// create user
func CreateUser(user *entity.User) (err error) {
	// 密码6位随机数
	rand.Seed(time.Now().UnixNano())
	min := 100000
	max := 999999
	randomNumber := rand.Intn(max-min+1) + min

	id := user.Id
	name := "user" + strconv.Itoa(randomNumber)
	avatarPath := "defaultAvatar.jpg"
	pwd := user.Password
	email := user.Email
	/*
		校验:
	*/
	//1. 密码长度校验，内容校验
	//	1.1 密码长度不超过20
	if n := len(pwd); n > 20 && n < 0 {
		return errors.ErrPWDFormat
	}
	// 1.2 密码只能包含 0-9，a-z，部分指定安全特殊字符
	pwdPattern := `^[a-z0-9!@#$%^&*()\-_=+\[\]{};':",./<>?]*$`
	matchedPwd, _ := regexp.MatchString(pwdPattern, pwd)
	if !matchedPwd {
		return errors.ErrPWDFormat
	}
	//2. 邮箱格式校验(后缀？是否有@？)
	emailPattern := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`
	matchedEmail, _ := regexp.MatchString(emailPattern, user.Email)
	if !matchedEmail && len(email) < 0 {
		return errors.ErrEmailFormat
	}
	//3. 名字校验(正则表达式，只能有英文字母和数字)
	user.Name = name
	namePattern := `^[a-zA-Z0-9]+$`
	matchedName, _ := regexp.MatchString(namePattern, user.Name)
	if !matchedName {
		return errors.ErrName
	}
	// 插入默认头像地址
	user.Avatar = avatarPath
	//4. 权限校验(不能创建role = 1 的用户)
	user.Role = 0
	// 首先检查是否已经存在了该用户对象
	var existUser entity.User
	if err := dao.SqlSession.Where("name = ? AND email = ?", name, email).First(&existUser).Error; err == nil {
		return errors.ErrUserAlreadyExists
	}
	if id < 0 {
		return errors.ErrUsrNotFound
	}

	// 加密密码
	hashedPwd, err := hashPassword(pwd)
	user.Password = string(hashedPwd)
	if err != nil {
		fmt.Println("encrypt password failed")
	}
	if err = dao.SqlSession.Create(user).Error; err != nil {
		return err
	}
	return
}

// 加密函数
func hashPassword(password string) ([]byte, error) {
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return nil, err
	}
	return hashedPassword, nil
}

// get all user information
func GetAllUser() (userList []*entity.User, err error) {
	if err := dao.SqlSession.Where("del_status = ?", 0).Find(&userList).Error; err != nil {
		return nil, err
	}
	return
}

// delete user
func DeleteUserById(id string) (err error) {
	// 先查询是否存在用户
	if err := dao.SqlSession.Where("id = ?", id).First(&entity.User{}).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.ErrUsrNotFound
		}
		return err
	}
	// 进行逻辑删除
	if err := dao.SqlSession.Model(&entity.User{}).Where("id = ?", id).Update("del_status", 1).Error; err != nil {
		return err
	}
	return nil
}

// / get user by id
func GetUserById(id string) (user *entity.User, err error) {
	user = &entity.User{}
	if err = dao.SqlSession.Where("id=?", id).First(user).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.ErrUsrNotFound
		}
		return nil, err
	}
	return user, nil
}

// update user information
func UpdateUser(user *entity.User) (err error) {
	// 更新后更新UpdateTime
	loc, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		fmt.Println("Error loading location:", err)
		return
	}
	currentTime := time.Now().In(loc)
	user.UpdateTime = currentTime

	if user.Password != "" {
		// 如果更新了密码， 就先校验，然后加密密码
		pwdPattern := `^[a-z0-9!@#$%^&*()\-_=+\[\]{};':",./<>?]*$`
		matchedPwd, _ := regexp.MatchString(pwdPattern, user.Password)
		if !matchedPwd || len(user.Password) > 20 {
			return errors.ErrPWDFormat
		}
		hashedPwd, _ := hashPassword(user.Password)
		user.Password = string(hashedPwd)
	}
	if user.Name != "" {
		//3. 名字校验(正则表达式，只能有英文字母和数字)
		namePattern := `^[a-zA-Z0-9]+$`
		matchedName, _ := regexp.MatchString(namePattern, user.Name)
		if !matchedName {
			return errors.ErrName
		}
	}
	err = dao.SqlSession.Model(&entity.User{}).Where("id = ?", user.Id).Updates(user).Error
	return err
}

// change user Role
func ChangeRole(userId int, newRole int) error {
	// 创建用户实例并设置新的角色
	user := &entity.User{
		Id:   userId,
		Role: newRole,
	}

	// 更新修改时间
	loc, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		fmt.Println("Error loading location:", err)
		return err
	}
	currentTime := time.Now().In(loc)
	user.UpdateTime = currentTime

	// 更新 Role 字段
	err = dao.SqlSession.Model(&entity.User{}).Where("id = ?", userId).UpdateColumns(map[string]interface{}{
		"Role":       user.Role,
		"UpdateTime": user.UpdateTime,
	}).Error
	if err != nil {
		fmt.Println("Error changing role:", err)
		return err
	}
	return nil
}

func LoginUser(req *entity.LoginRequest) (user *entity.User, err error) {
	if err := dao.SqlSession.Where("email = ?", req.Email).First(&user).Error; err != nil {
		return nil, errors.ErrEmail
	}
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil {
		return nil, errors.ErrPWD
	}
	return user, nil
}
